package top.huhuiyu.spirngboot2.total.service.impl;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import top.huhuiyu.spirngboot2.total.anno.Limit;
import top.huhuiyu.spirngboot2.total.aop.LimitMode;
import top.huhuiyu.spirngboot2.total.entity.AuthInfo;
import top.huhuiyu.spirngboot2.total.service.LimitService;
import top.huhuiyu.spirngboot2.total.service.RedisService;
import top.huhuiyu.spirngboot2.total.utils.AuthInfoUtils;

@Service
@RequiredArgsConstructor
@Slf4j
public class LimitServiceImpl implements LimitService {
    private final RedisService redisService;

    @Override
    public boolean checkLimit(Limit limit) {
        AuthInfo authInfo = AuthInfoUtils.authInfo();
        String key = String.format("limit_%s_%s", limit.key(), authInfo.getIp());
        Integer value = redisService.get(key, Integer.class);
        if (value == null) {
            redisService.save(key, 1, limit.time());
            return true;
        }
        // 没有通过就等待sleep时间之后再次尝试
        try {
            Thread.sleep(limit.sleep());
        } catch (Exception ex) {
        }
        value = redisService.get(key, Integer.class);
        if (value == null) {
            redisService.save(key, 1, limit.time());
            return true;
        }
        return false;
    }

    @Override
    public boolean checkBucketLimit(Limit limit) {
        // 桶限流不同模式有不同key
        AuthInfo authInfo = AuthInfoUtils.authInfo();
        String key = "bucket_limit_";
        if (limit.mode() == LimitMode.IP_BUCKET_LIMIT) {
            key += String.format("ip_%s_%s", authInfo.getIp(), limit.key());
        } else {
            key += limit.key();
        }
        // 限流操作
        Boolean result = redisService.hasKey(key);
        log.debug("限流信息：{},{}", key, result);
        // 没有key就新增一个
        if (!result) {
            redisService.save(key, 1, limit.time());
            return true;
        }
        // 读取限流的值
        Integer value = redisService.get(key, Integer.class);
        log.debug("限流次数信息：{}", value);
        // 判断是否超过限流值
        if (value < limit.limit()) {
            redisService.update(key, value + 1);
            return true;
        }
        return false;
    }
}
